package cn.fz.redisdemo01.service;

import cn.fz.redisdemo01.domain.dto.UserDto;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * 3. 注解驱动的缓存机制
 * Spring 提供了一组注解用于操作缓存，这些注解可以直接应用于方法上，使得代码更简洁。常用注解包括：
 *
 * @Cacheable：用于标记一个方法的返回值是可缓存的。下一次调用该方法时，Spring 会直接从缓存中返回结果，而不是再次执行方法。
 * @CachePut：在方法执行后将返回值放入缓存。它与 @Cacheable 的区别在于，@CachePut 不会跳过方法执行，而是始终执行方法并更新缓存。
 * @CacheEvict：用于清除缓存中的某些条目，可以指定缓存的 key 或清空整个缓存空间。
 * 原文链接：https://blog.csdn.net/u014390502/article/details/142713547
 */
@Service
public class UserService {
    /**
     * 解释：
     *
     * @Cacheable 用于缓存方法的返回值。
     * value = "user" 指定了缓存的名称，即 “user”。
     * key = "#p0" 指定了缓存的键值。这里的 #p0 是一个 SpEL 表达式，表示方法的第一个参数。
     * 在这个例子中，方法 getUserById 第一次被调用时，结果会缓存到 Redis 中，并与 user::id 作为 key 存储。后续相同 id 的请求将直接从缓存返回，而无需执行方法。
     * @param id
     * @return
     */
    // 当方法第一次调用时，结果将被缓存起来，之后相同参数的调用将直接从缓存中获取数据
    @Cacheable(value = "users", key = "#p0")
    public UserDto getUserById(Long id){
        // 模拟数据库查询操作
        System.out.println("Fetching user with id: " + id);
        return new UserDto(id, "User "+id);
    }

    /**
     * 3.2 @CachePut示例
     * 有时候，我们希望方法执行后，不仅返回结果，还更新缓存，这时可以使用 @CachePut 注解。
     * 解释：
     *
     * @CachePut 用于更新缓存中的值。
     * value = "user" 指定了缓存的名称，即 “user”。
     * key = "#p0.id" 指定了缓存的键值。这里的 #p0 是一个 SpEL 表达式，表示方法的第一个参数，即 User 对象。.id 表示取 User 对象的 id 属性作为缓存键。
     * 连续两次调用 curl "http://localhost:8080/api/redis/updAndSave?id=2" ，可以从日志中看到，每次方法都执行了，并且 user 对象加入到了缓存中。
     *
     * @param user
     * @return
     */
    // 无论缓存中是否存在数据，该方法都会被执行，并且返回值会更新缓存
    @CachePut(value = "user", key = "#p0.id")
    public UserDto updateUser(UserDto user) {
        System.out.println("Updating user with id: " + user.getId());
        // 模拟数据库更新操作
        user.setName("Updated " + user.getId());
        return user;
    }

    // 清除缓存中的指定用户数据
    @CacheEvict(value = "user", key = "#p0")
    public void deleteUser(Long id) {
        System.out.println("Deleting user with id: " + id);
        // 模拟数据库删除操作
    }

    // 清空整个缓存空间
    @CacheEvict(value = "user", allEntries = true)
    public void clearCache() {
        System.out.println("Clearing all user cache");
    }
}
